// Ch4_1.cpp : Initialization functions

// CH4_1.cpp
// by Charles Mc Auley
// "Programming AutoCAD 2000 with ObjectARX"
//
// This application demonstrates how to add
// new layer table records to the layer table.
// It also demonstrates how to use a layer table
// iterator

#include "StdAfx.h"
#include "StdArx.h"
#include "resource.h"

HINSTANCE _hdllInstance =NULL ;

// This command registers an ARX command.
void AddCommand(const char* cmdGroup, const char* cmdInt, const char* cmdLoc,
				const int cmdFlags, const AcRxFunctionPtr cmdProc, const int idLocal = -1);

// NOTE: DO NOT edit the following lines.
//{{AFX_ARX_MSG
void InitApplication();
void UnloadApplication();
//}}AFX_ARX_MSG

// NOTE: DO NOT edit the following lines.
//{{AFX_ARX_ADDIN_FUNCS
//}}AFX_ARX_ADDIN_FUNCS

/////////////////////////////////////////////////////////////////////////////
// DLL Entry Point
extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
{
	if (dwReason == DLL_PROCESS_ATTACH)
	{
        _hdllInstance = hInstance;
	} else if (dwReason == DLL_PROCESS_DETACH) {
	}
	return TRUE;    // ok
}



/////////////////////////////////////////////////////////////////////////////
// ObjectARX EntryPoint
extern "C" AcRx::AppRetCode 
acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt)
{
	switch (msg) {
	case AcRx::kInitAppMsg:
		// Comment out the following line if your
		// application should be locked into memory
		acrxDynamicLinker->unlockApplication(pkt);
		acrxDynamicLinker->registerAppMDIAware(pkt);
		InitApplication();
		break;
	case AcRx::kUnloadAppMsg:
		UnloadApplication();
		break;
	}
	return AcRx::kRetOK;
}


// Init this application. Register your
// commands, reactors...
void InitApplication()
{
	// NOTE: DO NOT edit the following lines.
	//{{AFX_ARX_INIT
	AddCommand("CH4_APPS", "CNL", "CNL", ACRX_CMD_MODAL, cnl);
	//}}AFX_ARX_INIT

	// TODO: add your initialization functions
	acutPrintf("Enter \"CNL\" to create a new layer.\n");
}

// Unload this application. Unregister all objects
// registered in InitApplication.
void UnloadApplication()
{
	// NOTE: DO NOT edit the following lines.
	//{{AFX_ARX_EXIT
	acedRegCmds->removeGroup("CH4_APPS");
	//}}AFX_ARX_EXIT

	acutPrintf("%s%s", "Goodbye\n", "Removing command group \"CH4_APPS\"\n");
}

// This functions registers an ARX command.
// It can be used to read the localized command name
// from a string table stored in the resources.
void AddCommand(const char* cmdGroup, const char* cmdInt, const char* cmdLoc,
				const int cmdFlags, const AcRxFunctionPtr cmdProc, const int idLocal)
{
	char cmdLocRes[65];

	// If idLocal is not -1, it's treated as an ID for
	// a string stored in the resources.
	if (idLocal != -1) {

		// Load strings from the string table and register the command.
		::LoadString(_hdllInstance, idLocal, cmdLocRes, 64);
		acedRegCmds->addCommand(cmdGroup, cmdInt, cmdLocRes, cmdFlags, cmdProc);

	} else
		// idLocal is -1, so the 'hard coded'
		// localized function name is used.
		acedRegCmds->addCommand(cmdGroup, cmdInt, cmdLoc, cmdFlags, cmdProc);
}

// This function called by 'cnl()' which is found on
// Ch4_1Commands.cpp
Adesk::Boolean getNewLyrLtId(AcDbObjectId& ltypeId)
{
	// We know that the linetype 'CONTINUOUS' exists
	// so give the user a choice of pressing [ENTER]
	// for 'CONTINUOUS' linetype or a listing option
	// to show all the linetype available or input a 
	// linetype name.

	char kw[20];
	char linType[50];
	char *pLtName;
	AcDbDatabase *pCurDb = NULL;
	AcDbLinetypeTable *pltTable;
	AcDbLinetypeTableRecord *pLtTableRcd;
	AcDbLinetypeTableIterator *pLtIterator;
	int rc;

	pCurDb = acdbHostApplicationServices()->workingDatabase();

	acedInitGet(NULL, "Name List Continuous");
	rc = acedGetKword("\nLinetype - [Name/List/Continuous]<Continuous>: ", kw);

	switch(rc)
	{
		case RTCAN:
			acutPrintf("\nUser canceled.");
			return Adesk::kFalse;
		case RTERROR:
			acutPrintf("\nFailed in getNewLyrLtId() function. ");
			return Adesk::kFalse;
		break;

		case RTNONE:
			pCurDb->getLinetypeTable(pltTable, AcDb::kForRead);
			pltTable->getAt("CONTINUOUS", ltypeId);
			pltTable->close();
			return Adesk::kTrue;
		break;

		case RTNORM:
			if(strcmp(kw, "Name") == 0)
			{
				rc = acedGetString(0, "\nEnter linetype string name: ", linType);
				switch(rc)
				{
					case RTCAN:
					case RTERROR:
						acutPrintf("\nError in retreiving linetype name.");
						return Adesk::kFalse;
					break;

					case RTNORM:
						if(linType[0] == '\0')
						{
							acutPrintf("\nNo layer name given.");
							return Adesk::kFalse;
						}

						// Check to see if the linetype
						// exists
						pCurDb->getLinetypeTable(pltTable, AcDb::kForRead);
						if(pltTable->has(linType))
						{
							// Retreive the AcDbObjecId of the layer table record
							pltTable->getAt(linType, ltypeId);
							pltTable->close();
							return Adesk::kTrue;
						}

						acutPrintf("\nLinetype '%s' does not exist using CONTINUOUS. ",
										linType);

						pltTable->getAt("CONTINUOUS", ltypeId);
						pltTable->close();
						return Adesk::kTrue;
					break;
				}// switch
			}// if
			else if(strcmp(kw, "List") == 0)
			{
				// Here we will use a Linetype Table Iteraror
				// to list out all the available linetype
				// and then ask the user to enter a
				// valid name for one of the layers

				acutPrintf("\nThe following linetypes are available. ");

				pCurDb->getLinetypeTable(pltTable, AcDb::kForRead);

				pltTable->newIterator(pLtIterator);
				for(; !pLtIterator->done(); pLtIterator->step())
				{
      
					// get the current linetype record from the iterator,
					// opened for read

			        pLtIterator->getRecord(pLtTableRcd, AcDb::kForRead);

					// get the linetype name from the linetype record
					// and store it in pLtName

					pLtTableRcd->getName(pLtName);

					// close the linetype record
					pLtTableRcd->close();
      
			        acutPrintf("\nLinetype name: %s", pLtName);

					delete [] pLtName;

				}// for

				// Don't forget to delete the iterator
				// that's your responsibility

				delete pLtIterator;

				rc = acedGetString(0, "\n\nEnter linetype string name: ", linType);
				switch(rc)
				{
					case RTCAN:
					case RTERROR:
						acutPrintf("\nError in retreiving linetype name.");
						return Adesk::kFalse;
					break;

					case RTNORM:
						if(linType[0] == '\0')
						{
							acutPrintf("\nNo layer name given.");
							return Adesk::kFalse;
						}

						// Check to see if the linetype
						// exists
						pCurDb->getLinetypeTable(pltTable, AcDb::kForRead);
						if(pltTable->has(linType))
						{
							// Retreive the AcDbObjecId of the layer table record
							pltTable->getAt(linType, ltypeId);
							pltTable->close();
							return Adesk::kTrue;
						}

						acutPrintf("\nLinetype '%s' does not exist using CONTINUOUS. ",
										linType);

						pltTable->getAt("CONTINUOUS", ltypeId);
						pltTable->close();
						return Adesk::kTrue;
					break;
				}// switch


			}
			else if(strcmp(kw, "Continuous") == 0)
			{
				// Remember the CONTINUOUS linetype always
				// exists in a drawing file.
				pCurDb->getLinetypeTable(pltTable, AcDb::kForRead);
				pltTable->getAt("CONTINUOUS", ltypeId);
				pltTable->close();
				return Adesk::kTrue;
			}
			else
			{
				return Adesk::kFalse;
			}
		break;

	}// switch

	return Adesk::kFalse;
}


// This function called by 'cnl()' which is found on
// Ch4_1Commands.cpp
void createNewLayer(char* lyrname, Adesk::UInt16 clr, AcDbObjectId ltypeId, Adesk::Boolean current)
{
	// We need to check if the layer name exists
	// If the layer name exists, apply the color
	// linetype id and whither to make it current
	// or not. In order to be current it cannot be
	// frozen, so we need to check for this also.
	// If the layer name does not exist we just create
	// a new layer with the properties contained in the arguments
	
	AcDbLayerTable *pLyrTable;
	AcDbLayerTableRecord *pLyrTblRecord;
	AcDbObjectId recId;

	AcCmColor color;
	color.setColorIndex(clr); // set color to parameter clr

	AcDbDatabase *pCurDb = NULL;

	pCurDb = acdbHostApplicationServices()->workingDatabase();


	pCurDb->getLayerTable(pLyrTable, AcDb::kForRead);
	// Check to see if the layer name exists
	if(pLyrTable->has(lyrname))
	{
		pLyrTable->getAt(lyrname, pLyrTblRecord, AcDb::kForWrite, Adesk::kFalse);
		// pLyrTblRecord now points at the layer table record
		// which was opened for write
		pLyrTblRecord->setIsFrozen(Adesk::kFalse);
		pLyrTblRecord->setColor(color);
		pLyrTblRecord->setLinetypeObjectId(ltypeId);

	}
	else
	{
		// Note how we can change the open mode
		// of the layer table from AcDb::kForRead
		// to AcDb::kForWrite

		pLyrTable->upgradeOpen();
		pLyrTblRecord = new AcDbLayerTableRecord;

		pLyrTblRecord->setName(lyrname);
		pLyrTblRecord->setColor(color);
		pLyrTblRecord->setLinetypeObjectId(ltypeId);

		pLyrTable->add(pLyrTblRecord);

	}

	// Get the layer Table ObjectId
	recId = pLyrTblRecord->objectId();

	pLyrTblRecord->close();
	pLyrTable->close();

	// Set the layer current if current
	// is equal to Adesk::kTrue
	// pCurDb is point to the current
	// drawing database
	// The database AcDbDatabase has a number of
	// query and edit functions for the header variables

	if(current)
	{
		pCurDb->setClayer(recId);
	}

}